//----------------------------------------------------
// Copyright (c) 2018, Djyos Open source Development team. All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------
// Copyright (c) 2018，著作权由都江堰操作系统开源开发团队所有。著作权人保留一切权利。
//
// 这份授权条款，在使用者符合下列条件的情形下，授予使用者使用及再散播本
// 软件包装原始码及二进位可执行形式的权利，无论此包装是否经改作皆然：
//
// 1. 对于本软件源代码的再散播，必须保留上述的版权宣告、本条件列表，以
//    及下述的免责声明。
// 2. 对于本套件二进位可执行形式的再散播，必须连带以文件以及／或者其他附
//    于散播包装中的媒介方式，重制上述之版权宣告、本条件列表，以及下述
//    的免责声明。

// 免责声明：本软件是本软件版权持有人以及贡献者以现状（"as is"）提供，
// 本软件包装不负任何明示或默示之担保责任，包括但不限于就适售性以及特定目
// 的的适用性为默示性担保。版权持有人及本软件之贡献者，无论任何条件、
// 无论成因或任何责任主义、无论此责任为因合约关系、无过失责任主义或因非违
// 约之侵权（包括过失或其他原因等）而起，对于任何因使用本软件包装所产生的
// 任何直接性、间接性、偶发性、特殊性、惩罚性或任何结果的损害（包括但不限
// 于替代商品或劳务之购用、使用损失、资料损失、利益损失、业务中断等等），
// 不负任何责任，即在该种使用已获事前告知可能会造成此类损害的情形下亦然。
//-----------------------------------------------------------------------------

#include <stdbool.h>
#include "stdint.h"
#include "stddef.h"
#include "mem_pub.h"
#include "cpu_peri.h"
#include "board.h"
#include "project_config.h"     //本文件由IDE中配置界面生成，存放在APP的工程目录中。
                                //允许是个空文件，所有配置将按默认值配置。

//@#$%component configure   ****组件配置开始，用于 DIDE 中图形化配置界面
//****配置块的语法和使用方法，参见源码根目录下的文件：component_config_readme.txt****
//%$#@initcode      ****初始化代码开始，由 DIDE 删除“//”后copy到初始化文件中
//%$#@end initcode  ****初始化代码结束

//%$#@describe      ****组件描述开始
//component name:"board config"//组件名
//parent:"none"                 //填写该组件的父组件名字，none表示没有父组件
//attribute:bsp                 //选填“third、system、bsp、user”，本属性用于在IDE中分组
//select:required               //选填“required、choosable、none”，若填必选且需要配置参数，则IDE裁剪界面中默认勾取，
                                //不可取消，必选且不需要配置参数的，或是不可选的，IDE裁剪界面中不显示，
//init time:early               //初始化时机，可选值：early，medium，later, pre-main。
                                //表示初始化时间，分别是早期、中期、后期
//dependence:"cpu onchip gpio"//该组件的依赖组件名（可以是none，表示无依赖组件），
                                //选中该组件时，被依赖组件将强制选中，
                                //如果依赖多个组件，则依次列出，用“,”分隔
//weakdependence:"none"         //该组件的弱依赖组件名（可以是none，表示无依赖组件），
                                //选中该组件时，被依赖组件不会被强制选中，
                                //如果依赖多个组件，则依次列出，用“,”分隔
//mutex:"none"                  //该组件的互斥组件名（可以是none，表示无互斥组件），
                                //如果与多个组件互斥，则依次列出，用“,”分隔
//%$#@end describe  ****组件描述结束

//%$#@configue      ****参数配置开始
#if ( CFG_MODULE_ENABLE_BOARD_CONFIG == false )
//#warning  " board_config  组件参数未配置，使用默认配置"
//%$#@target = header           //header = 生成头文件,cmdline = 命令行变量，DJYOS自有模块禁用
#define CFG_MODULE_ENABLE_BOARD_CONFIG    false //如果勾选了本组件，将由DIDE在project_config.h或命令行中定义为true
//%$#@num,0,100,
//%$#@enum,true,false,
//%$#@string,1,10,
//%$#select,        ***从列出的选项中选择若干个定义成宏
//%$#@free,
#endif
//%$#@end configue  ****参数配置结束
//@#$%component end configure


extern int djy_adc_read(uint16_t channel);


// =============================================================================
// 功能：用于设置系统时钟为180M，该函数在initcpu.S中调用，
// 参数：无
// 返回：无
// =============================================================================
extern UINT32 sctrl_ctrl(UINT32 cmd, void *param);
extern void sctrl_set_cpu_clk_dco(void);
extern void sctrl_dco_cali(UINT32 speed);
void InitOsClk_180M(void)
{
    u32 param;
    param = BLK_BIT_26M_XTAL | BLK_BIT_DPLL_480M | BLK_BIT_XTAL2RF | BLK_BIT_DCO;
    sctrl_ctrl(CMD_SCTRL_BLK_ENABLE, &param);

    sctrl_dco_cali(5);      //#define DCO_CALIB_180M          0x5
    sctrl_set_cpu_clk_dco();
}

// =============================================================================
// 功能：Board_GpioInit板上所有用到的GPIO初始化
//    在这里将所有可能用到的复用模式的gpio定义在这里需要用取消注释即可
//    建议不要删除
// 参数：无
// 返回：无
// =============================================================================
void Board_Init(void)
{
    extern void os_clk_init(void);
    extern s32 Djy_GpioInit(void);
    Djy_GpioInit();
    os_meminit();
    drv_model_init();
//  g_dd_init();
    sctrl_init();
    icu_init();
    wdt_init();
    gpio_init();
    flash_init();       //本函数不能放到ModuleInstall_Flash中，sctrl_sta_ps_init调用时需要访问flash设备。
    gdma_init();
    bk_timer_init();
    mpb_init();                         //暂时先放这里
    sctrl_sta_ps_init();
    pwm_init();         //用于os_clk_init做CPU时钟

    intc_init();
    os_clk_init();
    djy_gpio_mode(GPIO12,PIN_MODE_OUTPUT);         //485控制=接收
    djy_gpio_write(GPIO12,0);

    djy_gpio_mode(GPIO6,PIN_MODE_OUTPUT);           //左边紫外灯控制，1开0关
    djy_gpio_mode(GPIO24,PIN_MODE_OUTPUT);          //右边紫外灯控制，1开0关
    djy_gpio_mode(GPIO7,PIN_MODE_OUTPUT);           //左边照明灯控制，1开0关
    djy_gpio_mode(GPIO26,PIN_MODE_OUTPUT);          //右边照明灯控制，1开0关
    djy_gpio_mode(GPIO19,PIN_MODE_OUTPUT);          //左边门锁控制，1锁0开
    djy_gpio_mode(GPIO18,PIN_MODE_OUTPUT);          //右边门锁控制，1锁0开

    djy_gpio_mode(GPIO8,PIN_MODE_INPUT_PULLUP);     //左边门锁状态，1锁0开
    djy_gpio_mode(GPIO15,PIN_MODE_INPUT_PULLUP);    //右边门锁状态，1锁0开

    djy_gpio_mode(GPIO17,PIN_MODE_OUTPUT);     //板载LED DS9控制，1亮0灭
    djy_gpio_mode(GPIO34,PIN_MODE_OUTPUT);     //板载LED DS10控制，1亮0灭

    djy_gpio_mode(GPIO13,PIN_MODE_INPUT_PULLUP);    //进入测试状态的按钮，按住进测试模式
//  djy_gpio_mode(GPIO13,PIN_MODE_OUTPUT);    //进入测试状态的按钮，按住进测试模式

    u32 val;

    val = GFUNC_MODE_ADC4;
    sddev_control(GPIO_DEV_NAME, CMD_GPIO_ENABLE_SECOND, &val);
    val = GFUNC_MODE_ADC1;
    sddev_control(GPIO_DEV_NAME, CMD_GPIO_ENABLE_SECOND, &val);
    val = GFUNC_MODE_ADC5;
    sddev_control(GPIO_DEV_NAME, CMD_GPIO_ENABLE_SECOND, &val);
    val = GFUNC_MODE_ADC2;
    sddev_control(GPIO_DEV_NAME, CMD_GPIO_ENABLE_SECOND, &val);
}

void gpio13output(u32 val)
{
    djy_gpio_write(GPIO13,val);
}

void gpio17output(u32 val)
{
    djy_gpio_write(GPIO17,val);
}

void gpio34output(u32 val)
{
    djy_gpio_write(GPIO34,val);
}

void Board_UartHalfDuplexSend(u8 SerialNo)
{
    if(SerialNo == CN_UART1)
        djy_gpio_write(GPIO12,1);
    return;
}
void Board_UartHalfDuplexRecv(u8 SerialNo)
{
    if(SerialNo == CN_UART1)
        djy_gpio_write(GPIO12,0);
    return ;
}
#define CN_UVC_GPIO_LEFT        GPIO26
#define CN_UVC_GPIO_RIGHT       GPIO7
#define CN_LAMP_GPIO_LEFT       GPIO24
#define CN_LAMP_GPIO_RIGHT      GPIO6
#define CN_LOCK_GPIO_LEFT       GPIO18
#define CN_LOCK_GPIO_RIGHT      GPIO19
#define CN_STATUS_GPIO_LEFT     GPIO15
#define CN_STATUS_GPIO_RIGHT    GPIO8
#define CN_TEST_MODE_GPIO       GPIO13

//0关1开，下同
void UvcLeftCtrl(uint32_t val)
{
    djy_gpio_write(CN_UVC_GPIO_LEFT,val);
}

void UvcRightCtrl(uint32_t val)
{
    djy_gpio_write(CN_UVC_GPIO_RIGHT,val);
}

void LampLeftCtrl(uint32_t val)
{
    djy_gpio_write(CN_LAMP_GPIO_LEFT,val);
}

void LampRightCtrl(uint32_t val)
{
    djy_gpio_write(CN_LAMP_GPIO_RIGHT,val);
}

void LockLeftCtrl(uint32_t val)
{
    djy_gpio_write(CN_LOCK_GPIO_LEFT,val);
}

void LockRightCtrl(uint32_t val)
{
    djy_gpio_write(CN_LOCK_GPIO_RIGHT,val);
}

//获取锁的状态,1=锁上，0=没锁
u32 GetLockLeftStatus(void)
{
    return djy_gpio_read(CN_STATUS_GPIO_LEFT);
}

u32 GetLockRightStatus(void)
{
    return djy_gpio_read(CN_STATUS_GPIO_RIGHT);
}

#define CN_ONES_AD            5       //个位ADC通道
#define CN_TENS_AD            2       //十位ADC通道
#define CN_HUNDREDS_AD        1       //百位ADC通道

#define CN_TESTKEY_AD    4       //灯，紫外线，锁ADC通道

u32 GetSlaveAddr(void)
{
    u32 buf[5];
    u32 i,SlaveAddr;
    u32 ones = 0, tens = 0, hundreds = 0;
    s32 val = 0;
    bool_t flag = false;

    while(flag == false)
    {
        for(i = 0; i < 5; i++)
        {
            val = djy_adc_read(CN_ONES_AD);
            if((val <= 2400) && (val >= 0))
            {
                if(val > 2162)
                    ones = 0;
                else if(val > 1907)
                    ones = 1;
                else if(val > 1654)
                    ones = 2;
                else if(val > 1400)
                    ones = 3;
                else if(val > 1145)
                    ones = 4;
                else if(val > 891)
                    ones = 5;
                else if(val > 636)
                    ones = 6;
                else if(val > 382)
                    ones = 7;
                else if(val > 133)
                    ones = 8;
                else
                    ones = 9;
            }
            else
                return 0;

            val = djy_adc_read(CN_TENS_AD);
            if((val <= 2400) && (val >= 0))
            {
                if(val > 2162)
                    tens = 0;
                else if(val > 1907)
                    tens = 1;
                else if(val > 1654)
                    tens = 2;
                else if(val > 1400)
                    tens = 3;
                else if(val > 1145)
                    tens = 4;
                else if(val > 891)
                    tens = 5;
                else if(val > 636)
                    tens = 6;
                else if(val > 382)
                    tens = 7;
                else if(val > 133)
                    tens = 8;
                else
                    tens = 9;
            }
            else
                return 0;

            val = djy_adc_read(CN_HUNDREDS_AD);
            if((val <= 1200) && (val >= 0))
            {
                if(val > 397)
                    hundreds = 0;
                else
                    hundreds = 1;
            }
            else
                return 0;

            SlaveAddr = ones + (tens * 10) + (hundreds * 100);
            buf[i] = SlaveAddr;
        }

        for(i = 0; i < (5 - 1); i++)
        {
            if(buf[i] != buf[i+1])
                break;
        }
        if(i == 4)
            flag = true;
    }

//    printf("=============  SlaveAddr = %d ==============\r\n",SlaveAddr);
    return SlaveAddr;
}
//u32 GetTestMode(void)
//{
//    return djy_gpio_read(CN_TEST_MODE_GPIO);
//}

enum LED_UVC_LOCK GetLED_UVC_LOCK_Key (void)
{
    s32 val = 0;
    enum LED_UVC_LOCK key;

    val = djy_adc_read(CN_TESTKEY_AD);

//  val = djy_adc_read(CN_HUNDREDS_AD);
    if(val <= 2000)
    {
        if(val > 1000)
            key = Uvc_key;
        else
            key = Lock_key;
    }
    else if(djy_gpio_read(CN_TEST_MODE_GPIO))
        key = No_key;
    else
        key = Lamp_key;
    return key;
}


void Init_Cpu(void);
void SoftReset(void)
{
    Init_Cpu();
}

